package com.jt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;


@Component    //将该类交给spring容器管理
@Aspect   //定义切面类
@Order(2)  //执行顺序AOP第二个执行，数字越小越靠前
public class SpringAOP {
    /**
     * 公式： 切面=切入点表达式 + 停止方法
     * 切入点表达式：如果目标对象满足切入点表达式的判断
     *              则spring自动为其创建代理对象
     * 目标对象的bean的id：userServiceImpl
     * 切入点表达式：@Pointcut
     *      1.bean("bean的ID")
     *  AOP规则：如果目标对象满足切入点表达式，则执行通知方法
     *
     * */
    //@Pointcut("bean(userServiceImpl)")
    //@Pointcut("within(com.jt.service.UserServiceImpl)")
    //@Pointcut("within(com.jt.service..*)")
    //@Pointcut("execution(* com.jt.service.UserServiceImpl.addUser())")
    //@Pointcut("execution(* com.jt.service..*.*(..))")
    @Pointcut("@annotation(com.jt.anno.Gjh)")
    public void pointcut(){

    }
    //1.前置通知：在目标方法执行之前执行
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){//连接点：获取方法中的数据
        //获取目标对象的类型
        Class<?> targetClass = joinPoint.getTarget().getClass();
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取类名
        String className = joinPoint.getSignature().getDeclaringTypeName();
        Object[] objs = joinPoint.getArgs();
        System.out.println("我是前置通知");
        System.out.println("类型"+targetClass);
        System.out.println("方法名称"+methodName);
        System.out.println("类名"+className);
        System.out.println("方法中携带的参数"+ Arrays.toString(objs
        ));
    }
    //2.后置通知：在目标方法执行之后执行
    //通过returning = "result"属性，获取目标方法的返回值，当作参数传给result
    @AfterReturning(value = "pointcut()",returning = "result")
    public void afterReturning(Object result){
        System.out.println("我是后置通知");
        System.out.println("用户的返回值为："+result);
    }
    //3.异常通知：目标方法执行报错时，执行该通知
    @AfterThrowing(value = "pointcut()",throwing = "exception")
    public void afterThrow(Exception exception){
        System.out.println("我是异常通知");
        System.out.println("获取异常信息"+exception.getMessage());
        exception.printStackTrace();//所有异常
    }
    //4.最终通知：目标方法之后都要执行的通知
    @After("pointcut()")
    public void after(){
        System.out.println("我是最终通知，都要执行");
    }
    //5.（重点）环绕通知：在目标方法执行前后都要执行，控制目标方法
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint)throws Throwable{
        System.out.println("环绕通知执行前");
        Object result = joinPoint.proceed();
        System.out.println("环绕通知执行后");
        return result;
    }

}
